package org.jeecg.common.util.qws;

public final class Base64 {
	private static final char[] BASE64_CHAR = new char[]{'A', 'B', 'C', 'D',
			'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
			'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
			'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
			'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3',
			'4', '5', '6', '7', '8', '9', '+', '/'};
	private static final byte[] BASE64_BYTE = new byte[]{-1, -1, -1, -1, -1,
			-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
			-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
			-1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59,
			60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
			10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1,
			-1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
			38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1,
			-1, -1};

	public static final char[] encode(byte[] arg) {
		return encode(arg, 0, arg.length);
	}

	public static final byte[] decode(String arg) {
		return decode(arg.toCharArray());
	}

	public static final byte[] decode(char[] arg) {
		return decode(arg, 0, arg.length);
	}

	public static char[] encode(byte[] value, int startIndex, int endIndex) {
		if (value != null && value.length >= 1 && startIndex < endIndex
				&& startIndex >= 0 && endIndex <= value.length) {
			int length = (endIndex - startIndex) / 3 * 4;
			int n = (endIndex - startIndex) % 3;
			if (n != 0) {
				length += 4;
			}

			n = endIndex - n;
			char[] buf = new char[length];
			int i = startIndex;

			byte b1;
			byte b2;
			for (length = 0; i < n; length += 4) {
				b1 = value[i];
				b2 = value[i + 1];
				byte b3 = value[i + 2];
				buf[length] = BASE64_CHAR[b1 >> 2 & 63];
				buf[length + 1] = BASE64_CHAR[b1 << 4 & 48 | b2 >> 4 & 15];
				buf[length + 2] = BASE64_CHAR[b2 << 2 & 60 | b3 >> 6 & 3];
				buf[length + 3] = BASE64_CHAR[b3 & 63];
				i += 3;
			}

			switch (endIndex - n) {
				case 1 :
					b1 = value[n];
					buf[length] = BASE64_CHAR[b1 >> 2 & 63];
					buf[length + 1] = BASE64_CHAR[b1 << 4 & 48];
					buf[length + 2] = 61;
					buf[length + 3] = 61;
					break;
				case 2 :
					b1 = value[n];
					b2 = value[n + 1];
					buf[length] = BASE64_CHAR[b1 >> 2 & 63];
					buf[length + 1] = BASE64_CHAR[b1 << 4 & 48 | b2 >> 4 & 15];
					buf[length + 2] = BASE64_CHAR[b2 << 2 & 60];
					buf[length + 3] = 61;
			}

			return buf;
		} else {
			return new char[0];
		}
	}

	public static byte[] decode(char[] value, int startIndex, int endIndex) {
		if (value != null && value.length >= 1 && startIndex < endIndex
				&& startIndex >= 0 && endIndex <= value.length
				&& value[startIndex] != 61) {
			do {
				--endIndex;
			} while (value[endIndex] == 61);

			++endIndex;
			int length = (endIndex - startIndex) % 4;
			if (length > 0) {
				--length;
			}

			length += (endIndex - startIndex) / 4 * 3;
			byte[] buf = new byte[length];
			int n = endIndex - (endIndex - startIndex) % 4;
			int i = startIndex;

			byte b1;
			byte b2;
			byte b3;
			for (length = 0; i < n; length += 3) {
				b1 = BASE64_BYTE[value[i] & 127];
				b2 = BASE64_BYTE[value[i + 1] & 127];
				b3 = BASE64_BYTE[value[i + 2] & 127];
				byte b4 = BASE64_BYTE[value[i + 3] & 127];
				buf[length] = (byte) (b1 << 2 | b2 >> 4);
				buf[length + 1] = (byte) (b2 << 4 & 240 | b3 >> 2);
				buf[length + 2] = (byte) (b3 << 6 & 192 | b4);
				i += 4;
			}

			switch (endIndex - n) {
				case 2 :
					b1 = BASE64_BYTE[value[i] & 127];
					b2 = BASE64_BYTE[value[i + 1] & 127];
					buf[length] = (byte) (b1 << 2 | b2 >> 4);
					break;
				case 3 :
					b1 = BASE64_BYTE[value[i] & 127];
					b2 = BASE64_BYTE[value[i + 1] & 127];
					b3 = BASE64_BYTE[value[i + 2] & 127];
					buf[length] = (byte) (b1 << 2 | b2 >> 4);
					buf[length + 1] = (byte) (b2 << 4 & 240 | b3 >> 2);
			}

			return buf;
		} else {
			return new byte[0];
		}
	}
}